package clusteringAlg;

import java.util.Arrays;
import java.util.Random;

import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;


public class Sample {

	private Mat image;
	private int pose;
	private double scaledImage[];
	
	public Sample() {
		this.image = null;
		this.pose = -1;
		this.scaledImage = null;
	}
	
	/**
	 * @param image
	 * @param pose
	 * @param array
	 */
	public Sample(Mat image, int pose, double[] array) {
		super();
		this.image = image;
		this.pose = pose;
		this.scaledImage = array;
	}
	
	/**
	 * @param image
	 * @param pose
	 */
	
	public Sample(Mat image, int pose) {
		super();
		
		this.image = image;
		this.pose = pose;
		
		if (this.image != null){
			this.ScaleImage(0, 1);
		}

	}
	
	/**
	 * @param image
	 */
	
	public Sample(Mat image) {
		super();
		
		this.image = image;
		this.pose = -1;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((image == null) ? 0 : image.hashCode());
		result = prime * result + pose;
		result = prime * result + Arrays.hashCode(scaledImage);
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Sample other = (Sample) obj;
		if (image == null) {
			if (other.image != null)
				return false;
		} else if (!image.equals(other.image))
			return false;
		if (pose != other.pose)
			return false;
		if (!Arrays.equals(scaledImage, other.scaledImage))
			return false;
		return true;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Sample [image=" + image + ", pose=" + pose + ", scaledImage="
				+ Arrays.toString(scaledImage) + "]";
	}
	
	public void GaussianNoiseImage (double mi, double sigma){
		Mat m = this.image;
		int size = (int) m.total() * m.channels();
		double[] array = new double[size];
		
		this.image.get(0, 0, array);
		array = GaussianNoise(array, mi, sigma);
		this.image.put(0, 0, array);
		
	}
	
	public void GaussianNoiseScale (double mi, double sigma){

		this.scaledImage = GaussianNoise(this.scaledImage, mi, sigma);
	}
	
	public double[] GaussianNoise (double[] array, double mi, double sigma){
		Random r = new Random();
		
		for (int i=0; i<array.length; i++){
			array[i] = array[i] + (1/(Math.sqrt(2*Math.PI*Math.pow(sigma, 2)))) * Math.pow(Math.E,	-(Math.pow(r.nextInt(5), 2)/(2*Math.pow(sigma, 2))));
		}
		
		return array;
	}
	
	public void BlurImage(Size s){
		Imgproc.blur(this.image, this.image, s);
	}
	
	public void ScaleImage(double minVal, double maxVal){
		
		if (this.image == null)
			return;
		Mat m = this.image;
		int size = (int) m.total() * m.channels();
		double array[] = new double[size];
		
		this.image.get( 0, 0, array);
		
		this.scaledImage = this.ScaleData(array, minVal, maxVal);
	}
	
	public void SetImageFromScaledImage(double minVal, double maxVal){
		if (this.getScaledImage() == null)
			return;
		
		double array[] = this.ScaleData(this.scaledImage, minVal, maxVal);
		
		this.image.put(0, 0, array);
		
	}
	
	private double[] ScaleData(double[] array, double minVal, double maxVal){
		
		int i=0 ;
		double temp=0 , min = Double.MAX_VALUE, max = Double.MIN_VALUE;

		double[] scaledData = new double[array.length];
		
		for (i=0; i < array.length; i++){
			if (array[i] < min){
				min = array[i];
			}
			if (array[i] > max){
				max = array[i];
			}
		}
		
		for (i=0; i < array.length; i++){
			
			temp = array[i] - min;
			temp = ( (temp/ (max-min)) * (maxVal - minVal));
			temp += minVal;
			
			if ( temp > maxVal || temp < minVal)
				System.err.println("Error on Scale Data");
			
			scaledData[i]= temp;
		}
		
		return scaledData;
	}
	/**
	 * @return the image
	 */
	public Mat getImage() {
		return image;
	}

	/**
	 * @param image the image to set
	 */
	public void setImage(Mat image) {
		this.image = image;
	}
	
	public void setImage(Mat image, double minVal, double maxVal) {
		this.image = image;
		this.ScaleImage(minVal, maxVal);
	}

	/**
	 * @return the position
	 */
	public int getPose() {
		return pose;
	}

	/**
	 * @param position the position to set
	 */
	public void setPose(int pose) {
		this.pose = pose;
	}

	/**
	 * @return the array
	 */
	public double[] getScaledImage() {
		return scaledImage;
	}

	/**
	 * @param array the array to set
	 */
	public void setScaledImage(double[] array) {
		this.scaledImage = array;
	}
	
	public Sample clone(){
		
		Sample sample = new Sample(this.image.clone(), this.pose, this.scaledImage);
		
		return sample;
	}

}
